#include <gpiod.h> // 包含libgpiod库的头文件
#include <stdio.h> // 包含标准输入输出库
#include <sys/types.h>
#include <stdbool.h>
#include <string.h>
#include <time.h>
#include "snowboy/snowboy-detect-c-wrapper.h" // 唤醒词检测的头文件（在工程目录下）
#include "record.h"
#include "control.h"
#include "stt.h"
#include "tts.h"
#include "config.h"
#include "token.h"
#include "http.h"
#include "chat.h"

#define KEY1_LINE 9 // 定义GPIO线的编号，这里是PF9
#define KEY2_LINE 7
#define KEY3_LINE 8IEC958_AES1_CON_DCC
// 标志变量
bool is_recording = false; // 记录是否正在录音会议内容（key1）
bool is_chatting = false;  // 记录是否正在与大模型对话（key2）
bool is_talking = false;   // 记录用户是否正在说话
bool locked = false;       // 当执行某个按钮的功能时，关锁，禁止其它按钮的功能
bool has_launched = false; // 记录是否启动
// 按键引脚相关变量
struct gpiod_chip *chip; // 定义指向GPIO芯片的指针d
struct gpiod_line *key1; // 定义指向GPIO线的指针
struct gpiod_line *key2;
struct gpiod_line *key3;
int key1_v, last_key1_v; // 定义当前值和上一次的值，用于检测状态变化
int key3_v, last_key3_v;
int key2_v, last_key2_v;
// 录音相关变量
snd_pcm_uframes_t period = 999; // 周期大小
snd_pcm_t *capture = NULL;      // 声音采集设备句柄
char *buffer = NULL;            // 存放音频数据的缓冲区
FILE *pcm_file = NULL;          // 录音文件
// 热词检测变量
SnowboyDetect *detector = NULL;
int status = 0;
// 内存文件
FILE *memstream = NULL;
char *audio = NULL;
size_t audio_size = 0;
int silence = 0;               // 检测到连续的静音次数
char *meeting_contents = NULL; // 会议内容
// 音量设置相关变量
long volume = 0; // 初始音量
long volume_step = 10; // 每次调整的音量步长

int main(void)
{
    printf("<<< 欢迎使用智能会议助手，我是小智，有什么能帮到您的？\n");
    text_to_speech("欢迎使用智能会议助手，我是小智，有什么能帮到您的？");

    // 打开GPIO芯片
    chip = gpiod_chip_open_by_label("GPIOF");
    if (!chip)
    {
        perror("打开GPIO芯片失败");
        return 1;
    }

    // 获取GPIO线
    key1 = gpiod_chip_get_line(chip, KEY1_LINE);
    if (!key1)
    {
        perror("获取GPIO线失败");
        gpiod_chip_close(chip);
        return 1;
    }
    key2 = gpiod_chip_get_line(chip, KEY2_LINE);
    if (!key2)
    {
        perror("获取GPIO线失败");
        gpiod_chip_close(chip);
        return 1;
    }
    key3 = gpiod_chip_get_line(chip, KEY3_LINE);
    if (!key3)
    {
        perror("获取GPIO线失败");
        gpiod_chip_close(chip);
        return 1;
    }

    // 将GPIO线设置为输入模式
    if (gpiod_line_request_input(key1, "key1"))
    {
        perror("请求将GPIO线设置为输入模式失败");
        gpiod_chip_close(chip);
        return 1;
    }
    if (gpiod_line_request_input(key2, "key2"))
    {
        perror("请求将GPIO线设置为输入模式失败");
        gpiod_chip_close(chip);
        return 1;
    }
    if (gpiod_line_request_input(key3, "key3"))
    {
        perror("请求将GPIO线设置为输入模式失败");
        gpiod_chip_close(chip);
        return 1;
    }

    // 获取初始的GPIO线值
    last_key1_v = gpiod_line_get_value(key1);
    last_key2_v = gpiod_line_get_value(key2);
    last_key3_v = gpiod_line_get_value(key3);

    // 无限循环检测GPIO线值的变化
    while (1)
    {
        // 获取当前的GPIO线值
        key1_v = gpiod_line_get_value(key1);
        key2_v = gpiod_line_get_value(key2);
        key3_v = gpiod_line_get_value(key3);

        // 如果当前值与上一次的值不同，说明按键状态发生了变化
        if (key1_v != last_key1_v)
        {
            // 如果当前值为0，表示按键被按下
            if (!locked && key1_v == 0 && !is_recording)
            {
                locked = true; // 关锁，禁止其他按键响应
                // key1按下且未开始录音，开始录音
                capture = record_start("hw:0,1", SND_PCM_FORMAT_S16_LE, 1, 16000, &period);
                if (!capture)
                {
                    continue;
                }

                buffer = malloc(snd_pcm_frames_to_bytes(capture, period));
                if (!buffer)
                {
                    perror("malloc");
                    record_stop(capture);
                    continue;
                }

                pcm_file = fopen("meeting.pcm", "wb");
                if (!pcm_file)
                {
                    perror("Error opening output file");
                    free(buffer);
                    record_stop(capture);
                    continue;
                }

                is_recording = true;
                printf("<<< 开始记录会议内容:\n");
            }
            else if (key1_v == 0 && is_recording)
            {
                // key1按下且正在录音，结束录音
                record_stop(capture);
                capture = NULL;
                free(buffer);
                buffer = NULL;
                is_recording = false;
                printf("<<< 会议内容记录完毕！\n");

                // 读取音频文件
                size_t size;
                buffer = load_audio_file("meeting.pcm", &size);
                if (!buffer)
                {
                    printf("<<< 读取音频文件失败\n");
                }

                // 录音转文本
                meeting_contents = speech_to_text(buffer, size);

                // 判断文本合法性
                if (0 == strcmp(meeting_contents, ""))
                {
                    printf("<<< 会议内容为空，生成总结失败！\n");
                    free(buffer);
                    buffer = NULL;
                    locked = false;
                    continue;
                }
                printf("<<< 会议内容如下: \n>>> %s\n", meeting_contents);

                // 发送给大模型作总结
                char *answer = chat(meeting_contents);
                strcat(meeting_contents, " 为这次会议内容生成总结");
                // printf("%s\n", meeting_contents);
                if (answer)
                {
                    printf("<<< 总结内容如下：\n<<< %s\n", answer);
                }
                else
                {
                    printf("<<< 生成总结失败！\n");
                }

                free(buffer);
                buffer = NULL;

                locked = false; // 开锁，允许其他按键响应
            }

            last_key1_v = key1_v;
        }

        if (key2_v != last_key2_v)
        {
            if (!locked && key2_v == 0 && !is_chatting)
            {
                locked = true;

                // 创建snowboy检测器
                detector = SnowboyDetectConstructor("common.res", "meeting.pmdl");
                if (!detector)
                {
                    continue;
                }

                capture = record_start("hw:0,1", SND_PCM_FORMAT_S16_LE, 1, 16000, &period);
                if (!capture)
                {
                    SnowboyDetectDestructor(detector);
                    continue;
                }

                buffer = malloc(snd_pcm_frames_to_bytes(capture, period)); // 分配缓冲区
                if (!buffer)
                {
                    perror("malloc");
                    record_stop(capture);
                    SnowboyDetectDestructor(detector);
                    continue;
                }

                is_chatting = true;
                printf("<<< 您好，我叫小智，很高兴为您服务！\n");
            }
            else if (key2_v == 0 && is_chatting)
            {
                SnowboyDetectDestructor(detector);
                record_stop(capture);
                capture = NULL;
                is_chatting = false;
                printf("<<< 感谢您的使用，再见！\n");
                locked = false;
            }

            last_key2_v = key2_v;
        }

        if (key3_v != last_key3_v)
        {
            if (!locked && key3_v == 0)
            {
                locked = true;

                // 发送开会提醒邮件
                const char *url = "http://192.168.43.245:5000/send_email";
                const char *json_data = "{\"content\":\"<p>七月七日上午10:00在教8楼答辩</p>\"}";
                int result = send_email(url, json_data);
                if (result == 0)
                {
                    printf("<<< 邮件发送成功!\n");
                }
                else
                {
                    printf("<<< 邮件发送失败!\n");
                }

                locked = false;
            }
            last_key3_v = key3_v;
        }

        if (is_recording && capture)
        {
            // 录音开始且音频设备打开成功，进行录音
            snd_pcm_sframes_t frames = snd_pcm_readi(capture, buffer, period); // 从PCM设备读取数据
            if (frames < 0)
            {
                fprintf(stderr, "Error from read: %s\n", snd_strerror(frames));
                snd_pcm_recover(capture, frames, 0); // 处理欠载和过载问题
            }

            fwrite(buffer, snd_pcm_frames_to_bytes(capture, frames), 1, pcm_file); // 将读取的数据写入文件
        }

        if (is_chatting && detector)
        {
            snd_pcm_sframes_t frames = snd_pcm_readi(capture, buffer, period);
            if (frames < 0)
            {
                fprintf(stderr, "Error from read: %s\n", snd_strerror(frames));
                snd_pcm_recover(capture, frames, 0);
                continue;
            }
            status = SnowboyDetectRunDetection(detector, (int16_t *)buffer, snd_pcm_frames_to_bytes(capture, frames) / sizeof(int16_t), 0);
            // 检测到说话声，开始录音
            if (status >= 0)
            {
                if (!memstream)
                {
                    // 打开内存文件
                    memstream = open_memstream(&audio, &audio_size);
                    if (!memstream)
                    {
                        perror("open_memstream");
                        continue;
                    }
                    is_talking = true;
                }
            }
            // 检测到持续2秒的静音，结束录音
            if (is_talking)
            {
                if (status == -2)
                {
                    silence++;
                }
                if (status == 0)
                {
                    silence = 0;
                }
                if (silence > 32)
                {
                    is_talking = false;
                    printf("<<< 正在为您解答，请稍后！\n");
                    silence = 0;
                    if (memstream)
                    {
                        fclose(memstream);
                        memstream = NULL;
                    }

                    if (audio_size)
                    {
                        // 暂停录音
                        snd_pcm_drop(capture);

                        // 录音转文本
                        char *text = speech_to_text(audio, audio_size);
                        if (text)
                        {
                            printf(">>> %s\n", text);
                        }

                        // 语音控制结束
                        if (0 == strcmp(text, "再见。"))
                        {
                            SnowboyDetectDestructor(detector);
                            record_stop(capture);
                            capture = NULL;
                            is_chatting = false;
                            printf("<<< 感谢您的使用，再见！\n");
                            text_to_speech("感谢您的使用，再见！");
                            locked = false;
                            continue;
                        }

                        // 音量控制
                        if (0 == strcmp(text, "加大音量。"))
                        {
                            printf("<<< 好的,为您提高音量: \n");
                            volume = get_playback_volume("hw:0", "Analog");
                            set_playback_volume("hw:0", "Analog", volume + volume_step);
                            printf("<<< 当前音量：%ld\n", volume + volume_step);
                        }
                        else if (0 == strcmp(text, "减小音量。"))
                        {
                            printf("<<< 好的,为您降低音量: \n");
                            volume = get_playback_volume("hw:0", "Analog");
                            set_playback_volume("hw:0", "Analog", volume - volume_step);
                            printf("<<< 当前音量：%ld\n", volume - volume_step);
                        }
                        else
                        {
                            // 将文本发送给大模型
                            char *answer = chat(text);
                            if (answer)
                            {
                                printf("<<< %s\n", answer);
                            }
                            else
                            {
                                printf("<<< 抱歉，我没听清楚，请重新提问。\n");
                                answer = "抱歉，我没听清楚，请重新提问。";
                            }

                            // 回答内容转语音
                            text_to_speech(answer);
                        }
                        
                        // 恢复录音
                        snd_pcm_prepare(capture);
                        printf("<<< 您可以继续提问：\n");
                    }
                }

                if (memstream)
                {
                    fwrite(buffer, 1, snd_pcm_frames_to_bytes(capture, frames), memstream);
                }
            }
        }
    }

    // 关闭GPIO芯片
    gpiod_chip_close(chip);
    return 0;
}